// ServidorPais.cc


#include "ServidorPais.h"
#include <stdio.h>
#include <stdlib.h>


extern "C" {
	#include </usr/include/signal.h>
}

namespace PracticaCaso {
	ServidorPais::ServidorPais(int p, string m): TcpListener(p) {
		this->pais = p;
		this->fichero = m;
		this->loadMappings(fichero);
	}

	ServidorPais::ServidorPais(const ServidorPais& ns): TcpListener(ns.port) {
		pais = ns.pais;
	}


	ServidorPais::~ServidorPais() {
		cout << "ServidorPais destructor called" << endl;
	}


	ServidorPais& ServidorPais::operator = (const ServidorPais& rhs) {
		// check for identity
		if (this == &rhs) return *this;
		pais = rhs.pais;
		return *this;
	}


	void ServidorPais::loadMappings(string mappingsFileName) {
		char line[1024];
		ifstream in(mappingsFileName.c_str());
		if(!in) {
			cout << "Cannot open file: " << mappingsFileName << endl;
			exit(1);
		}

		while (!in.eof()) {
			in.getline(line, 1024, '\n');
			// Process the line.
			if (((string)line).find("#") == 0) {
				continue;
			}
			istringstream ist(line);
			string word[2];
			ist >> word[0];
			if (!(ist >> word[1])) {
				if (this->domain.length() == 0) {
					this->domain = word[0];
				}
			} else {
				this->dns2IpPortMap[word[0]] = word[1];
			}
		}
		in.close();
	}
	
	string ServidorPais::puntos(string dnsName) {
		map<string, string>::iterator p;
		string dnsValue;

		p = (this->dns2IpPortMap).find(dnsName);
		if (p != this->dns2IpPortMap.end()) {
			dnsValue = p->second;
		} else {
			int npos = dnsName.rfind(this->domain);
			// If our domain is part of the dnsName passed
			if (npos>=0 && npos < dnsName.length()) {
				// redirect to one of the dns name server children
				typedef map<string, string>::const_iterator CI;
				for (CI p = (this->dns2IpPortMap).begin(); p != (this->dns2IpPortMap).end(); ++p) {
					if (p->first.length() > this->domain.length()) {
						npos =  (dnsName).rfind(p->first);
					}
				}
				dnsValue = "ERROR: domain cannot be resolved in NS " + this->domain + ": " + dnsName;
			}
		}
		return dnsValue; //dnsName;
	}


	ServidorPaisThread::~ServidorPaisThread() {
		delete this->dnsClient;
	}

	void ServidorPaisThread::run() {
		// make the type casting and recuperate the parameters using "arg"
		string cadena = (this->dnsClient)->receive();
		cout << "Recibido del Cliente " << cadena << endl;
		char* p;
		char* d;
		char* t;
		char* s;
		char* c;

		char * pch;
		pch = strtok (const_cast<char*> ( cadena.c_str() )," ");
		p = pch; // Pais
		pch = strtok (NULL, " ");
		d = pch; // canciones por disco
		pch = strtok (NULL, " ");
		t = pch; // discos totales
		pch = strtok (NULL, " ");
		c = pch; // colaboraciones
		float cancionDisco = (atof(d) / atof(dnsServer.puntos("D").c_str())) * 50;
		float discoTotal = (atof(t) / atof(dnsServer.puntos("T").c_str())) * 50;
		float colaboracion = (atof(c) / atof(dnsServer.puntos("C").c_str())) * 50;
		cout << "puntos en cada categoria: " << cancionDisco << " " << discoTotal << " " << colaboracion << endl; 
		float suma = cancionDisco + discoTotal + colaboracion;
		cout << "La suma es: " << suma << endl;
		char puntoc[30];
		sprintf(puntoc,"%f",suma);
		(this->dnsClient)->send(puntoc);
	}


	ostream & operator << (ostream & os, ServidorPais &t) {
		os << "server_socket: " << t.server_socket << " - port: " << t.port << " - domain: " << t.domain << endl;
		
		return os;
	}
}


// global variable
PracticaCaso::ServidorPais * ServidorPais_pointer;

// function called when CTRL-C is pressed
void ctrl_c(int)
{
    printf("\nCTRL-C was pressed...\n");
	ServidorPais_pointer->stop();

}


void usage() {
	cout << "Usage: ServidorPais <puerto> <fichero-de-paises>" << endl; //Para no leer el fichero de caché
	exit(1);
}



int main(int argc, char** argv) {

	signal(SIGINT,ctrl_c);
	if (argc != 3) {
		usage();
	}
	PracticaCaso::ServidorPais ServidorPais(atoi(argv[1]), (string)argv[2]);
	cout << "ServidorPais instance: " << endl << ServidorPais << endl;
	ServidorPais_pointer = &ServidorPais;
	ServidorPais.start();
	while (true) {
		PracticaCaso::TcpClient *client = ServidorPais.acceptTcpClient();
		if (client) {
			PracticaCaso::ServidorPaisThread* t = new PracticaCaso::ServidorPaisThread(client, ServidorPais);
			t->start();
		} else {
			break;
		}
	}
	ServidorPais.stop();
}
